package com.r2coding.article.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.r2coding.article.annotation.SysLog;
import com.r2coding.article.dao.ArticleDao;
import com.r2coding.article.dao.LabelDao;
import com.r2coding.article.entity.ArticleEntity;
import com.r2coding.article.entity.LabelEntity;
import com.r2coding.article.service.LabelService;
import com.r2coding.article.vo.DateCountVo;
import com.r2coding.article.vo.req.CategoryReqVo;
import com.r2coding.article.vo.req.GetArticlesByIdReqVo;
import com.r2coding.article.vo.req.UpdateCategoryReqVo;
import com.r2coding.article.vo.resp.*;
import com.r2coding.common.enums.Module;
import com.r2coding.common.enums.OperationType;
import com.r2coding.common.exception.BizCode;
import com.r2coding.common.exception.ServiceException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.r2coding.common.util.PageUtils;
import com.r2coding.common.util.Query;

import com.r2coding.article.dao.CategoryDao;
import com.r2coding.article.entity.CategoryEntity;
import com.r2coding.article.service.CategoryService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 * 文章分类信息实现类
 *
 * @author 98k灬
 * @email hk666zx@163.com
 * @date 2022-04-13 19:34:16
 */
@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private LabelDao labelDao;

    @Autowired
    private LabelService labelService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @SysLog(module = Module.ARTICLE, operationType = OperationType.DELETE, description = "删除分类")
    //@CacheEvict(value = {"base"}, key = " 'selectBase' ") // 删除缓存
    @Override
    public void deleteCategory(Integer id) {
        // 1、判断该分类下是否有文章引用
        QueryWrapper<ArticleEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("category_id", id);
        List<ArticleEntity> articles = articleDao.selectList(wrapper);

        // 1、判断该分类下是否有标签
        QueryWrapper<LabelEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("category_id", id);
        List<LabelEntity> labels = labelDao.selectList(queryWrapper);

        if (!CollectionUtils.isEmpty(articles) || !CollectionUtils.isEmpty(labels)) {
            throw new ServiceException(BizCode.CATEGORY_OCCUPY);
        }
        this.removeById(id);
    }

    @SysLog(module = Module.ARTICLE, operationType = OperationType.UPDATE, description = "更新分类")
    @Transactional
    @Override
    public void updateCategory(UpdateCategoryReqVo reqVo) {
        Integer categoryId = reqVo.getCategoryId();
        // 更新该分类下面的标签信息
        if (!CollectionUtils.isEmpty(reqVo.getLabelIds())) {
            // 先将该分类下的所有标签全部删除
            QueryWrapper<LabelEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("category_id", categoryId);
            List<LabelEntity> labelList = labelDao.selectList(wrapper);
            if (!CollectionUtils.isEmpty(labelList)) {
                for (LabelEntity label : labelList) {
                    labelDao.updateLabelCategoryIdNull(label.getLabelId());
                }
            }
            // 再将新的标签添加到该分类下
            for (Integer labelId : reqVo.getLabelIds()) {
                LabelEntity label = labelDao.selectById(labelId);
                if (label != null) {
                    label.setUpdateTime(new Date());
                    label.setCategoryId(categoryId);
                    labelDao.updateById(label);
                }
            }
        }
        // 更新该分类的基本信息
        CategoryEntity category = new CategoryEntity();
        category.setUpdateTime(new Date());
        category.setName(reqVo.getName());
        category.setCategoryId(categoryId);
        this.baseMapper.updateById(category);
    }

    @Override
    public List<CategoryCount> getCategoryCount() {
        List<Integer> ids = articleDao.selectAllCategoryId();
        if (CollectionUtils.isEmpty(ids)) {
            return null;
        }
        List<CategoryCount> result = new ArrayList<>();
        for (Integer id : ids) {
            CategoryEntity category = this.baseMapper.selectById(id);
            // 根据分类id查询文章信息
            QueryWrapper<ArticleEntity> wrapper = new QueryWrapper<>();
            wrapper.eq("category_id", id);
            wrapper.eq("is_public", 1);
            List<ArticleEntity> list = articleDao.selectList(wrapper);

            CategoryCount categoryCount = new CategoryCount();
            categoryCount.setCategoryId(id);
            categoryCount.setName(category.getName());
            int count = CollectionUtils.isEmpty(list) ? 0 : list.size();
            categoryCount.setValue(count);
            result.add(categoryCount);
        }
        return result;
    }

    @Cacheable(value = "categoryCountResp", key = " 'CATEGORY_COUNT' ")
    @Override
    public List<CategoryCountResp> categoryCount() {
        List<CategoryCountRespVo> categoryCountRespVos = new ArrayList<>();
        List<LabelListRespVo> labelList = labelService.labelList();
        List<CategoryEntity> categoryList = this.baseMapper.selectList(null);
        if (!CollectionUtils.isEmpty(categoryList)) {
            for (CategoryEntity categoryEntity : categoryList) {
                CategoryCountRespVo categoryCountRespVo = new CategoryCountRespVo();
                categoryCountRespVo.setCategory(categoryEntity);
                categoryCountRespVos.add(categoryCountRespVo);
            }
        }

        if (!CollectionUtils.isEmpty(labelList) && !CollectionUtils.isEmpty(categoryCountRespVos)) {
            for (LabelListRespVo label : labelList) {
                for (CategoryCountRespVo category : categoryCountRespVos) {
                    if (category.getCategory().getCategoryId() == label.getLabel().getCategoryId()) {
                        category.setCount(category.getCount() + label.getCount());
                    }
                }
            }
        }

        List<CategoryCountResp> collect = new ArrayList<>();
        if (!CollectionUtils.isEmpty(categoryCountRespVos)) {
            collect = categoryCountRespVos.stream().map(item -> {
                CategoryCountResp resp = new CategoryCountResp();
                resp.setValue(item.getCount());
                resp.setName(item.getCategory().getName());
                return resp;
            }).collect(Collectors.toList());
        }

        return collect;
    }

    @Override
    public PageInfo<ArticleEntity> getArticlesById(GetArticlesByIdReqVo reqVo) {
        PageHelper.startPage(reqVo.getCurrent(), reqVo.getSize());
        QueryWrapper<ArticleEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("category_id", reqVo.getCategoryId());
        wrapper.orderByDesc("create_time");
        wrapper.eq("is_public", 1);
        List<ArticleEntity> articleEntities = articleDao.selectList(wrapper);
        return new PageInfo<>(articleEntities);
    }

    @Cacheable(value = "contributeDateRespVo", key = " 'CONTRIBUTE_DATE' ")
    @Override
    public ContributeDateRespVo getContributeDate() {
        ContributeDateRespVo respVo = new ContributeDateRespVo();
        List<String> year = this.getAllDateYear();
        List<String> contributeDate = new ArrayList<>();
        contributeDate.add(year.get(0));
        contributeDate.add(year.get(year.size()-1));
        respVo.setContributeDate(contributeDate);

        List<DateCountVo> dateCountVoList = articleDao.getDateCountVo();
        List<List<Object>> blogContributeCount = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dateCountVoList)) {
            year.forEach( item -> {
                List<Object> objList = new ArrayList<>();
                objList.add(item);
                boolean flag = false;
                for (DateCountVo vo : dateCountVoList) {
                    if (item.equals(vo.getDate())) {
                        flag = true;
                        break;
                    }
                }

                if (flag) {
                    dateCountVoList.forEach( dateCount -> {
                        if (item.equals(dateCount.getDate())) {
                            objList.add(dateCount.getCount());
                        }
                    });
                } else {
                    objList.add(0);
                }
                blogContributeCount.add(objList);
            });
            respVo.setBlogContributeCount(blogContributeCount);
            return respVo;
        } else {
            return null;
        }
    }

    private List<String> getAllDateYear() {
        List<String> list = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        for(int i = 365; i >= 0; i--) {
            Calendar c = Calendar.getInstance();
            c.setTime(new Date());
            c.add(Calendar.DATE, - i);
            Date d = c.getTime();
            String day = format.format(d);
            list.add(day);
        }
        return list;
    }

    @Override
    public ArticleRespVo getByCategoryId(CategoryReqVo req) {
        QueryWrapper<ArticleEntity> wrapper1 = new QueryWrapper<>();
        wrapper1.eq("is_public", 1);
        wrapper1.eq("category_id", req.getCategoryId());
        List<ArticleEntity> list1 = articleDao.selectList(wrapper1);
        ArticleRespVo respVo = new ArticleRespVo();
        respVo.setSize(list1.size());
        PageHelper.startPage(req.getCurrent(), req.getSize());
        QueryWrapper<ArticleEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("is_public", 1);
        wrapper.eq("category_id", req.getCategoryId());
        List<ArticleEntity> list = articleDao.selectList(wrapper);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<CategoryRespVo> collect = list.stream().map(item -> {
            CategoryRespVo vo = new CategoryRespVo();
            BeanUtils.copyProperties(item, vo);
            if (vo.getTitle().length() > 10) {
                String s = vo.getTitle().substring(0, 10);
                vo.setTitle(s + "...");
            }
            // 根据分类id查询分类名称
            CategoryEntity category = this.baseMapper.selectById(vo.getCategoryId());
            vo.setCategoryName(category.getName());
            return vo;
        }).collect(Collectors.toList());
        respVo.setRespVoList(collect);
        return respVo;
    }

    @Cacheable(value = "categoryEntity", key = " 'CATEGORY_LIST' ")
    @Override
    public List<CategoryEntity> categoryList() {
        QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("create_time");
        return this.baseMapper.selectList(wrapper);
    }
}